package ch.poole.openinghoursfragment.templates;

import ch.poole.openinghoursfragment.LogUtil;
import ch.poole.openinghoursfragment.ResourceTable;
import ch.poole.openinghoursfragment.Util;
import ch.poole.openinghoursfragment.ValueWithDescription;
import ch.poole.openinghoursfragment.menu.Menu;
import ch.poole.openinghoursfragment.menu.MenuItem;
import ch.poole.openinghoursfragment.menu.MeunItemType;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.data.rdb.RdbStore;
import ohos.data.resultset.ResultSet;
import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;
import ohos.utils.net.Uri;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import static ohos.agp.components.Component.HIDE;
import static ohos.agp.components.Component.VISIBLE;

public class TemplateMangementDialog extends AbilitySlice implements UpdateCursorListener {
    public static final String DEBUG_TAG = "TemplateMangementDialog";
    private static final String MANAGE_KEY = "manage";
    private static final String KEY_KEY = "key";
    private static final String REGION_KEY = "region";
    private static final String OBJECT_KEY = "object";
    private static final String CURRENT_KEY = "current";
    private static final String TAG = "management_fragment";
    private static final int READ_CODE = 23456;
    private static final int READ_REPLACE_CODE = 34567;
    private static final int WRITE_CODE = 24679;
    /**
     * Template database related methods and fields
     */
    private ValueWithDescription key;
    private String current;

    private UpdateTextListener updateListener;
    private RdbStore readableDb;
    private boolean manage;
    private String region;
    private String object;
    private TemplateAdapter itemProvider;
    private ArrayList<TemplateBean> date;

    public TemplateMangementDialog(UpdateTextListener updateListener) {
        this.updateListener = updateListener;
    }

    public Intent getParamIntent(boolean manage, @NotNull ValueWithDescription key, String region, String object, @NotNull String currentText) {
        Intent intent = new Intent();
        intent.setParam(MANAGE_KEY, manage);
        intent.setParam(KEY_KEY, key);
        intent.setParam(REGION_KEY, region);
        intent.setParam(OBJECT_KEY, object);
        intent.setParam(CURRENT_KEY, currentText);
        return intent;
    }


    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        if (intent != null) {
            manage = intent.getBooleanParam(MANAGE_KEY, false);
            key = intent.getSequenceableParam(KEY_KEY);
            region = intent.getStringParam(REGION_KEY);
            object = intent.getStringParam(OBJECT_KEY);
            current = intent.getStringParam(CURRENT_KEY);
            if (!manage && null == updateListener) {
                throw new IllegalStateException("parent must implement UpdateTextListener");
            }
        }
        super.setUIContent(ResourceTable.Layout_template_list);

        final Text headTitle = (Text) findComponentById(ResourceTable.Id_headTitle);
        try {
            final String manageStr = getResourceManager().getElement(ResourceTable.String_manage_templates_title).getString();
            final String loadStr = getResourceManager().getElement(ResourceTable.String_load_templates_title).getString();
            headTitle.setText(manage ? manageStr : loadStr);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NotExistException e) {
            e.printStackTrace();
        } catch (WrongTypeException e) {
            e.printStackTrace();
        }

        final DirectionalLayout fab = (DirectionalLayout) findComponentById(ResourceTable.Id_more);
        final ListContainer lv = (ListContainer) findComponentById(ResourceTable.Id_listView1);
        date = getDate();
        itemProvider = new TemplateAdapter(getContext(), date, manage);
        lv.setItemProvider(itemProvider);
        final Text done = (Text) findComponentById(ResourceTable.Id_done);
        done.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {

                if (readableDb != null) {
                    readableDb.close();
                }
                terminate();
            }
        });
        if (manage || key != null || region != null || object != null) {
            fab.setVisibility(VISIBLE);
            fab.setClickedListener(v -> {
                Menu popup = new Menu(getContext(), fab);
                popup.setShowBootom(true);
                // menu items
                MenuItem showAll = popup.add(MeunItemType.NO_SUB, ResourceTable.String_spd_ohf_show_all);
                showAll.setOnMenuItemClickListener(item -> {
                    newCursor(readableDb);
                    return true;
                });

                if (manage) {
                    MenuItem loadTemplate = popup.add(MeunItemType.NO_SUB, ResourceTable.String_spd_ohf_save_to_file);
                    loadTemplate.setOnMenuItemClickListener(item -> {
                        Intent i = new Intent();
                        i.setAction("android.intent.action.CREATE_DOCUMENT");
                        i.setType("*/*");
                        startAbilityForResult(i, WRITE_CODE);
                        return true;
                    });
                    MenuItem saveTemplate = popup.add(MeunItemType.NO_SUB, ResourceTable.String_spd_ohf_load_from_file_replace);
                    saveTemplate.setOnMenuItemClickListener(item -> {
                        Intent i = new Intent();
                        i.setAction("android.intent.action.OPEN_DOCUMENT");
                        i.setType("*/*");
                        i.addFlags(Intent.FLAG_NOT_OHOS_COMPONENT);
                        startAbilityForResult(i, READ_REPLACE_CODE);
                        return true;
                    });
                    MenuItem manageTemplate = popup.add(MeunItemType.NO_SUB, ResourceTable.String_spd_ohf_load_from_file);
                    manageTemplate.setOnMenuItemClickListener(item -> {
                        Intent i = new Intent();
                        i.setAction("android.intent.action.OPEN_DOCUMENT");
                        i.setType("*/*");
                        i.addFlags(Intent.FLAG_NOT_OHOS_COMPONENT);
                        startAbilityForResult(i, READ_CODE);
                        return true;
                    });
                }
                popup.showPop();// showing popup menu
            });
        } else {
            fab.setVisibility(HIDE);
        }


    }

    private ArrayList<TemplateBean> getDate() {
        ArrayList<TemplateBean> templateList = new ArrayList<>();
        readableDb = new TemplateDatabaseHelper(getContext()).getDb();
        ResultSet resultSet = TemplateDatabase.queryBy(readableDb, null, null, null);
        if (resultSet.goToFirstRow()) {
            do {
                int id = resultSet.getInt(resultSet.getColumnIndexForName("_id"));
                boolean isDefault = resultSet.getInt(resultSet.getColumnIndexForName(TemplateDatabase.DEFAULT_FIELD)) == 1;
                String nameValue = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.NAME_FIELD));
                String keyValue = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.KEY_FIELD));
                String regionValue = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.REGION_FIELD));
                String objectValue = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.OBJECT_FIELD));
                String template = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.TEMPLATE_FIELD));
                templateList.add(new TemplateBean(id, isDefault, nameValue, keyValue, regionValue, objectValue, template));
            } while (resultSet.goToNextRow());
        }
        return templateList;
    }


    @Override
    protected void onStop() {
        super.onStop();
        if (readableDb != null && readableDb.isOpen()) {

            readableDb.close();
        }
    }

    private class TemplateAdapter extends BaseItemProvider {
        final boolean manage;
        final ArrayList<TemplateBean> dateList;
        final Context context;
        final Map<String, String> regionsMap = new HashMap<>();


        /**
         * Adapter to the template database
         *
         * @param context  Context
         * @param dateList dateList
         * @param manage   if true start the TemplateDialog otherwise select the tempplate
         */
        public TemplateAdapter(@NotNull Context context, @NotNull ArrayList<TemplateBean> dateList, boolean manage) {
            super();
            this.manage = manage;
            this.dateList = dateList;
            this.context = context;

            // setting up the region spinner is a bit involved as we want to be able to sort it
            final String[] entries;
            final String[] values;
            try {
                entries = getResourceManager().getElement(ResourceTable.Strarray_region_entries).getStringArray();
                values = getResourceManager().getElement(ResourceTable.Strarray_region_values).getStringArray();
                for (int i = 0; i < values.length; i++) {
                    regionsMap.put(values[i], entries[i]);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NotExistException e) {
                e.printStackTrace();
            } catch (WrongTypeException e) {
                e.printStackTrace();
            }
        }


        private String valueToEntry(int valuesId, int entriesId, @Nullable String value) {
            final String[] values;
            final String[] entries;
            try {
                values = context.getResourceManager().getElement(valuesId).getStringArray();
                entries = context.getResourceManager().getElement(entriesId).getStringArray();
                for (int i = 0; i < values.length; i++) {
                    if ((value == null && "".equals(values[i]) || (value != null && value.equals(values[i])))) {
                        return entries[i];
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NotExistException e) {
                e.printStackTrace();
            } catch (WrongTypeException e) {
                e.printStackTrace();
            }
            return "Invalid value";
        }

        @Override
        public int getCount() {
            return dateList == null ? 0 : dateList.size();
        }

        @Override
        public Object getItem(int i) {
            if (dateList != null && i >= 0 && i < dateList.size()) {
                return dateList.get(i);
            }
            return null;
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
            Component cpt = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_template_list_item, null, false);
            TemplateBean sampleItem = dateList.get(i);
            Logger.getLogger("TemplateDialog").log(Level.WARNING, "打印22222id:" + sampleItem.getId());
            cpt.setTag(sampleItem.getId());
            Text nameView = (Text) cpt.findComponentById(ResourceTable.Id_name);
            nameView.setText(sampleItem.getNameValue());
            Text metaView = (Text) cpt.findComponentById(ResourceTable.Id_meta);

            String keyEntry = null;
            try {
                keyEntry = context.getResourceManager().getElement(ResourceTable.String_spd_ohf_meta).getString(valueToEntry(ResourceTable.Strarray_key_values, ResourceTable.Strarray_key_entries, sampleItem.getKeyValue()));
                keyEntry = sampleItem.isDefault() ? context.getResourceManager().getElement(ResourceTable.String_is_default).getString(keyEntry) : keyEntry;
                keyEntry = sampleItem.getObjectValue() != null ? context.getResourceManager().getElement(ResourceTable.String_spd_ohf_with_object).getString(keyEntry, sampleItem.getObjectValue()) : keyEntry;
                metaView.setText(keyEntry);
                Text regionView = (Text) cpt.findComponentById(ResourceTable.Id_region);
                if (sampleItem.getRegionValue() != null) {
                    regionView.setVisibility(VISIBLE);
                    String region = context.getResourceManager().getElement(ResourceTable.String_spd_ohf_region).getString(regionsMap.get(sampleItem.getRegionValue()));
                    regionView.setText(region);
                } else {
                    regionView.setVisibility(HIDE);
                }


                final String template = sampleItem.getTemplate();
                if (manage) {
                    cpt.setClickedListener(v -> {
                        Integer localId = (Integer) cpt.getTag();
                        final TemplateDialog templateDialog = TemplateDialog.newInstance(current, key, true, localId != null ? localId : -1, context);
                        templateDialog.setmUpdateCursorListener(TemplateMangementDialog.this);
                        present(templateDialog, new Intent());
                    });
                } else {
                    cpt.setClickedListener(v -> {
                        updateListener.updateText(template);
                        TemplateMangementDialog.this.dismissAllowingStateLoss();
                    });
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NotExistException e) {
                e.printStackTrace();
            } catch (WrongTypeException e) {
                e.printStackTrace();
            }
            return cpt;
        }
    }

    private void dismissAllowingStateLoss() {
        terminate();
    }

    @Override
    protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
        super.onAbilityResult(requestCode, resultCode, resultData);
        if (resultData == null) {
            LogUtil.error("null data in onAbilityResult");
            return;
        }
        if (requestCode == WRITE_CODE) {
            Uri uri = resultData.getUri();
            if (uri != null) {
                RdbStore readableDb = new TemplateDatabaseHelper(getContext()).getDb();
                try {
                    OutputStream outputStream = DataAbilityHelper.creator(getContext()).obtainOutputStream(uri);
                    TemplateDatabase.writeJSON(readableDb, outputStream);
                } catch (DataAbilityRemoteException e) {
                    e.printStackTrace();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        } else if (requestCode == READ_CODE || requestCode == READ_REPLACE_CODE) {

            Uri uri = resultData.getUri();
            if (uri != null) {
                boolean worked = false;


                try {
                    InputStream inputStream = DataAbilityHelper.creator(getContext()).obtainInputStream(uri);
                    worked = TemplateDatabase.loadJson(readableDb, inputStream, requestCode == READ_REPLACE_CODE);

                } catch (DataAbilityRemoteException e) {
                    e.printStackTrace();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    newCursor(readableDb);
                }

                if (!worked) {
                    final String string;
                    try {
                        string = getContext().getResourceManager().getElement(ResourceTable.String_spd_ohf_toast_file_read_failure).getString();
                        Util.toastTop(getContext(), string);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (NotExistException e) {
                        e.printStackTrace();
                    } catch (WrongTypeException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    @Override
    public void newCursor(@NotNull final RdbStore db) {
        ResultSet resultSet = TemplateDatabase.queryBy(db, null, null, null);
        date.clear();
        if (resultSet.goToFirstRow()) {
            do {
                int id = resultSet.getInt(resultSet.getColumnIndexForName("_id"));
                Logger.getLogger("TemplateDialog").log(Level.WARNING, "打印id:" + id);
                boolean isDefault = resultSet.getInt(resultSet.getColumnIndexForName(TemplateDatabase.DEFAULT_FIELD)) == 1;
                String nameValue = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.NAME_FIELD));
                String keyValue = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.KEY_FIELD));
                String regionValue = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.REGION_FIELD));
                String objectValue = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.OBJECT_FIELD));
                String template = resultSet.getString(resultSet.getColumnIndexForName(TemplateDatabase.TEMPLATE_FIELD));
                date.add(new TemplateBean(id, isDefault, nameValue, keyValue, regionValue, objectValue, template));
            } while (resultSet.goToNextRow());
        }
        getUITaskDispatcher().delayDispatch(new Runnable() {
            @Override
            public void run() {
                itemProvider.notifyDataChanged();
            }
        }, 200);
    }
}
